package com.clp.protocol.iec104.apdu.asdu.info_obj;

import com.clp.protocol.core.common.frame.time2a.CP56Time2a;
import com.clp.protocol.core.common.frame.time2a.Time2a;
import com.clp.protocol.iec104.apdu.asdu.info_obj.info_elem.InfoElem;
import com.clp.protocol.iec104.apdu.asdu.info_obj.qua.Qua;
import com.clp.protocol.iec104.definition.TypeTag;
import io.netty.buffer.ByteBuf;
import lombok.Getter;

import java.util.Objects;

/**
 * 地址连续的信息体对象
 */
@Getter
public abstract class CInfoObj implements InfoObj {
    /**
     * 信息元素地址（3字节）
     */
    private int addr;
    /**
     * 信息内容
     */
    private InfoElem infoElem;
    /**
     * 限定词（如果是遥测限定词会保存品质描述词）
     */
    private Qua qua;
    /**
     * 时标
     */
    private CP56Time2a time2a;

    public CInfoObj(int addr) {
        this.addr = addr;
    }

    @Override
    public CInfoObj initBy(ByteBuf buf) {
        checkTypeTag();
        TypeTag typeTag = typeTag();
        // 1、设置信息元素地址（已经在构造时赋予了）
        // 2、设置信息元素内容
        if (typeTag.hasInfoElem()) {
            this.infoElem = typeTag.newInvalidInfoElem().initBy(buf);
        }
        // 3、设定限定词（如果有）
        if (typeTag.hasQua()) {
            this.qua = typeTag.newInvalidQua().initBy(buf);
        }
        // 4、设定时标（如果有）
        if (typeTag.hasTime2a()) {
            this.time2a = Time2a.newInvalidCP56Time2a().initBy(buf);
        }
        return this;
    }

    @Override
    public boolean isValid() {
        if (!hasTypeTag()) return false;
        if (addr < 0) return false;
        if (typeTag().hasInfoElem() && (infoElem == null || !infoElem.isValid())) return false;
        if (typeTag().hasQua() && (qua == null || !qua.isValid())) return false;
        return !typeTag().hasTime2a() || (time2a != null && time2a.isValid());
    }

    @Override
    public void writeTo(ByteBuf buf) {
        TypeTag typeTag = typeTag();
        // 连续的信息体不需要写入地址值
        // 写入信息元素内容（如果有）
        if (typeTag.hasInfoElem()) {
            infoElem.writeTo(buf);
        }
        // 写入限定词的值（如果有）
        if (typeTag.hasQua()) {
            qua.writeTo(buf);
        }
        // 获取时标（如果有）
        if (typeTag.hasTime2a()) {
            time2a.writeTo(buf);
        }
    }

    @Override
    public String toString() {
        return "信息体地址：" + addr + "， 信息内容：" + infoElem + ", 限定词：" + qua + ", 时标：" + time2a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CInfoObj cInfoObj = (CInfoObj) o;
        return addr == cInfoObj.addr && Objects.equals(infoElem, cInfoObj.infoElem) && Objects.equals(qua, cInfoObj.qua) && Objects.equals(time2a, cInfoObj.time2a);
    }

    @Override
    public int hashCode() {
        return Objects.hash(addr, infoElem, qua, time2a);
    }
}
